Docker で Rails 7 + React + MySQL の環境を構築する
https://gyazo.com/ba83d40a6ec0f6652f7428fa644ad5ac
久しぶりに Rails アプリケーションを構築することになったので、初期構築方法をメモする。
まずは docker-compose のドキュメントに従って進めるが、 Ruby 2.3 の時代から変わってなさそうなので随時変更していく。
Rails プロジェクトの設定
まずは Dockerfile.development の作成をする。
Rails 7.1 から、 rails new したときに本番用の Dockerfile が生成されて上書きされてしまうので開発環境用のものと分けておく。
※今回は自分で作成した Dockerfile を利用するが、公式で出ているものをマルチステージで作ったほうがよさそう。今後検討したい。
React も欲しいので、 Node.js も先にインストールしておく。
package.json と yarn.lock は初め存在しないので、コメントアウトしておく。
code:Dockerfile
FROM ruby:3.2.3
ENV NODE_MAJOR=18
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev ca-certificates gnupg
RUN mkdir -p /etc/apt/keyrings && \
apt-get update && apt-get install nodejs -y && \
apt-get install npm -y && \
npm install yarn -g -y
RUN mkdir /app
WORKDIR /app
ADD Gemfile /app/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
ADD package.json yarn.lock /app/
RUN yarn install
ADD . /app
Gemfile と Gemfile.lock も用意しておく。
Gemfile.lock は空ファイルで良い。
code:Gemfile
gem 'rails', '7.0.8'
docker-compose で MySQL も一緒に作成する。
Rails コンテナが web サービスでは、 node_modules と vendor はマウントしたくないので、別ボリュームを作成して割り当てている。
code:docker-compose.yml
version: '3'
services:
db:
image: mysql:8.0
volumes:
- db-store:/var/lib/mysql
environment:
MYSQL_DATABASE: rails_development
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: root
TZ: Asia/Tokyo
web:
build:
context: .
dockerfile: Dockerfile.development
command: sh -c "rm -f tmp/pids/server.pid && ./bin/dev"
stdin_open: true
volumes:
- .:/app
- node-modules-store:/app/node_modules
- vendor-store:/app/vendor
ports:
- "3000:3000"
depends_on:
- db
volumes:
db-store:
node-modules-store:
vendor-store:
ここまで準備できたら、以下のコマンドを実行する。
JavaScript のバンドラーには esbuild を利用する。
昔は webpacker が利用されていたが、最近だと esbuild の方が良さそうだ。(Webpacker が非推奨になり、後継の snakapacker になったようだが。。)
code:bash
docker-compose run web rails new . --force --database=mysql --javascript=esbuild --css=tailwind
これでプロジェクトファイルが生成されているはず。
初回起動までの設定
docker イメージのビルド時に node_modules 以下に大量のライブラリがあると ADD できなくなってしまうので、 dockerignore に追加しておく。
※ Rails 7.1 以降はこのファイルも生成されるので不要。
code:.dockerignore
node_modules
vendor
Rails サーバーだけの起動であれば、 bin/rails s で良いが、 bin/dev で動かせば JS のビルドも動かすことができる。
その定義は Procfile.dev に記載されている。
Docker コンテナで動かす場合にはポートバインディングを指定しておいた方が良い。
※ Rails 7.1 以降はこのファイルも生成されるので不要。
code:Procfile.dev
web: env RUBY_DEBUG_OPEN=true bin/rails server -b 0.0.0.0 -p 3000
js: yarn build --watch
css: yarn build:css --watch
データベースの設定値を変更しておく。
code:config/database.rb
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: root
host: db
これで localhost:3000 でアクセスできるはず。
React のインストール
まずはコンテナ内に react をインストールする。
code:bash
yarn add react react-dom
esbuild は追加ライブラリなしで typescript のトランスパイルを実施してくれるよう。
ただ、スクリプトを以下のように書き換える。
code:package.json
{
// ...
"scripts": {
"build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=/assets --loader:.js=jsx --loader:.ts=tsx",
// ...
}
// ...
}
tailwind を使用している場合は、 tailwind の設定ファイルに以下を追加する。(ここはよく分かってない)
code:tailwind.config.js
'./app/javascript/**/*.jsx',
'./app/javascript/**/*.tsx'
例えば以下のようなコンポーネントを作成し、ビューに組み込むと表示できると思う。
code:/app/javascript/HomeIndex.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
export const HomeIndex = () => {
return (
<>
<h2>Hello from React</h2>
</>
);
};
const container = document.getElementById('homeIndex');
const root = createRoot(container);
root.render(<HomeIndex />);
code:/app/views/home/index.html/erb
<div id="homeIndex"></div>
<%= javascript_include_tag "HomeIndex", defer: true %>